package com.winit.tree.manager;

import com.winit.common.base.bean.ExecuteResult;
import com.winit.commons.util.SeqGenerate;
import com.winit.flow.model.Flow;
import com.winit.flow.web.FlowController;
import com.winit.tree.model.TreeNode;
import com.winit.tree.model.TreeType;
import com.winit.tree.repository.TreeRepository;
import com.winit.tree.repository.TreeRepositoryExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Component
public class TreeManager {

    private static Logger log = LoggerFactory.getLogger(TreeManager.class);

    @Autowired
    private TreeRepository treeRepository;
    @Autowired
    private TreeRepositoryExt treeRepositoryExt;
//    @Autowired
//    private FlowManager flowManager;

    public TreeNode getTree(String treeId, String type) {
        TreeNode root = null;
        if (StringUtils.isEmpty(treeId)) {
            root = this.getRootNode(type);
        } else {
            root = this.treeRepository.findOne(treeId);
        }
        if (null == root) {
            return null;
        }
        this.getRawTree(root);
        return root;
    }

    public FlowController.FlowTreeNode getTreeNode(String treeId) {
        TreeNode treeNode = this.treeRepository.findOne(treeId);
        FlowController.FlowTreeNode flowTreeNode = new FlowController.FlowTreeNode();
        flowTreeNode.setId(treeNode.getId());
        flowTreeNode.setType("1");
        flowTreeNode.setParentId(treeNode.getParentId());
        flowTreeNode.setIsDel(treeNode.getIsDel());
        flowTreeNode.setLevel(treeNode.getLevel());
        flowTreeNode.setName(treeNode.getName());
        flowTreeNode.setMetaData(treeNode);
        List<FlowController.FlowTreeNode> flowTreeNodes = new ArrayList<>();
        flowTreeNode.setChildren(flowTreeNodes);
        return flowTreeNode;
    }

    private TreeNode getRawTree(TreeNode treeNode) {
        List<TreeNode> children = new ArrayList<>();
        if (StringUtils.isEmpty(treeNode.getChildsort())) {
            children = this.treeRepository.findByParentIdAndIsDel(treeNode.getId(), "1");
        } else {
            children = this.treeRepository.findByParentIdAndIsDel(treeNode.getId(), "1", treeNode.getChildsort());
        }

        if (children == null) {
            children = new ArrayList<>();
        }
        treeNode.setChildren(children);
        if (!CollectionUtils.isEmpty(children)) {
            for (TreeNode child : children) {
                this.getRawTree(child);
            }
        }
        return treeNode;
    }

    private TreeNode getRootNode(String type) {
        return treeRepository.findByParentIdAndIsDelAndType("-1", "1", type).get(0);
    }


    public ExecuteResult createTreeNode(TreeNode treeNode) {
        ExecuteResult executeResult = this.checkTreeNodeCreate(treeNode);
        if (!executeResult.success()) {
            return executeResult;
        }
        String id = null;
        switch (treeNode.getType()) {
            case TreeType.PRODUCT_LINE:
                id = SeqGenerate.createId("PDL");
                break;
            case TreeType.FLOW_FRAME:
                id = SeqGenerate.createId("FFR");
                break;
            default:
                log.error("不受支持的tree type:" + treeNode.getType());
                executeResult.toError("不受支持的tree type");
                return executeResult;
        }

        treeNode.setId(id);
        treeNode.setIsDel("1");
        this.treeRepository.save(treeNode);
        addChildSort(treeNode.getParentId(), id);
        executeResult.setData(treeNode);
        return executeResult;
    }

    private ExecuteResult checkTreeNodeCreate(TreeNode treeNode) {
        ExecuteResult executeResult = new ExecuteResult();
        String parentId = treeNode.getParentId();
        if (StringUtils.isEmpty(parentId)) {
            executeResult.toError("parent id不能为空");
            return executeResult;
        }
        TreeNode parent = this.treeRepository.findOne(parentId);
        if ("-1".equals(parentId)) { //为根节点，type不能为空
            if (StringUtils.isEmpty(treeNode.getType())) {
                executeResult.toError("root节点的type不能为空");
                return executeResult;
            }
            treeNode.setLevel("0");
        } else {
            if (parent == null) {    //非空节点，parent一定存在
                executeResult.toError("parent不存在");
                return executeResult;
            } else {
                if (StringUtils.isEmpty(treeNode.getType())) {  //有parent的正常情况，检查type字段是否为空
                    treeNode.setType(parent.getType());
                } else if (!treeNode.getType().equalsIgnoreCase(parent.getType())) {
                    executeResult.toError("tree与parent type 不一致");
                    return executeResult;
                }
            }
        }
        if (StringUtils.isEmpty(treeNode.getLevel())) {
            executeResult.toError("level不能为空");
            return executeResult;
        }
        return executeResult;
    }

    public ExecuteResult updateTreeNode(TreeNode treeNode) {
        TreeNode node = this.treeRepository.findOne(treeNode.getId());
        if (!node.getParentId().equals(treeNode.getParentId())) {
            deleteChildSort(node.getParentId(), treeNode.getId());
            addChildSort(treeNode.getParentId(), treeNode.getId());
        }
        this.treeRepositoryExt.updateByPropertyNotNull(treeNode);
        return new ExecuteResult();
    }

    public ExecuteResult deleteTreeNodeById(String treeNodeId) {
        ExecuteResult rs = this.checkTreeNodeDelete(treeNodeId);
        if (!rs.success()) {
            return rs;
        }
        this.deleteTreeNodeById(treeNodeId, true);
        return rs;
    }

    public void deleteTreeNodeById(String treeId, boolean recursive) {
        //TODO flow与product_line没有关系了
//        this.flowManager.updateExistFlowForProductLineDelete(treeId);
        TreeNode node = this.treeRepository.findOne(treeId);
        deleteChildSort(node.getParentId(), treeId);
        if (!recursive) {
            this.treeRepository.delete(treeId);
            return;
        }
        List<TreeNode> children = this.treeRepository.findByParentId(treeId);
        this.treeRepository.delete(treeId);
        if (CollectionUtils.isEmpty(children)) {
            return;
        }
        for (TreeNode child : children) {
            this.deleteTreeNodeById(child.getId(), recursive);
        }
    }

    private ExecuteResult checkTreeNodeDelete(String treeId) {
        TreeNode dbTreeNode = this.treeRepository.findOne(treeId);
        if (null == dbTreeNode) {
            return ExecuteResult.getErrorExecuteResult("指定的tree node不存在", null);
        }
//        if ("0".equals(dbProductLine.getIsDel())){
//            return ExecuteResult.getErrorExecuteResult("指定的business已被删除", null);
//        }
        return new ExecuteResult();
    }


    public List<TreeNode> getAllFlowFrame() {
        return this.treeRepository.findByTypeAndIsDelNot(TreeType.FLOW_FRAME, "0");
    }

    //修改子节点顺序
    public void saveChildSort(String treeId, String sort) {
        TreeNode dbTreeNode = this.treeRepository.findOne(treeId);
        if (null == dbTreeNode) {
            log.error("com.winit.tree.manager.TreeManager.saveChildSort 找不到节点 treeId=" + treeId);
            return;
        }
        dbTreeNode.setChildsort(sort);
        treeRepository.save(dbTreeNode);
    }

    public void deleteChildSort(String parentId, String childId) {
        if (StringUtils.isEmpty(parentId) || StringUtils.isEmpty(childId)) {
            return;
        }
        TreeNode dbTreeNode = this.treeRepository.findOne(parentId);
        if(null == dbTreeNode || StringUtils.isEmpty(dbTreeNode.getChildsort())){
            return;
        }
        dbTreeNode.setChildsort(dbTreeNode.getChildsort().replace(childId + ",", ""));
        treeRepository.save(dbTreeNode);
    }

    public void addChildSort(String parentId, String childId) {
        if (StringUtils.isEmpty(parentId) || StringUtils.isEmpty(childId)) {
            return;
        }
        TreeNode dbTreeNode = this.treeRepository.findOne(parentId);
        if(null == dbTreeNode){
            return;
        }
        dbTreeNode.setChildsort(dbTreeNode.getChildsort() + childId + ",");
        treeRepository.save(dbTreeNode);
    }

}
